package com.zheng;

import com.zheng.classloader.MyClassLoader;
import com.zheng.mappper.Context;
import com.zheng.mappper.Host;
import com.zheng.mappper.Mapper;
import com.zheng.mappper.Wrapper;
import com.zheng.process.RequestProcessor;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.*;

/**
 *  @author: zheng
 *  @Date: 2020-06-23 14:48
 *  @Description: tomcat 启动类
 */
public class BootStrap {

    private Mapper mapper=new Mapper();



    public static void main(String[] args) {
        BootStrap bootStrap=new BootStrap();
        try {
            //启动类初始化，把server.xml文件读取进来，根据配置文件
            //去加载路径下的servlet，并把映射信息Host->Context->Wrapper->Servlet信息封装在mapper中
            bootStrap.init();
            //启动程序
            bootStrap.start();
        } catch (IOException e) {
            e.printStackTrace();
        }


    }



    private void start() throws IOException {
        //定义一个线程池
        int corePoolSize=10;
        int maxPollSize=50;
        long keepAliveTime=100l;
        TimeUnit unit=TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQue=new ArrayBlockingQueue<>(100);
        ThreadFactory threadFactory=Executors.defaultThreadFactory();
        RejectedExecutionHandler handler=new ThreadPoolExecutor.AbortPolicy();
        ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(
                corePoolSize,
                maxPollSize,
                keepAliveTime,
                unit,
                workQue,
                threadFactory,
                handler
        );
        //定义socket通信
        ServerSocket serverSocket=new ServerSocket(Integer.parseInt(mapper.getPort()));

        while (true){
            Socket socket=serverSocket.accept();
            RequestProcessor requestProcessor=new RequestProcessor(socket,mapper);
            threadPoolExecutor.execute(requestProcessor);
        }

    }

    private void init() {
        //加载xml文件server.xml
        InputStream resourceAsStream=this.getClass().getClassLoader().getResourceAsStream("server.xml");
        SAXReader saxReader=new SAXReader();

        try {
            Document document=saxReader.read(resourceAsStream);
            Element rootElement=document.getRootElement();

            //获取端口号
            Element connector= (Element) rootElement.selectSingleNode("//Connector");
            String port=connector.attributeValue("port");
            mapper.setPort(port);
            List<Host> hostList=new ArrayList<>();
            List<Element> hostListElement=rootElement.selectNodes("//Host");
            for(int i=0;i<hostListElement.size();i++){
                Element hostElement=hostListElement.get(i);
                String hostName=hostElement.attributeValue("name");
                String appbase=hostElement.attributeValue("appbase");
                Host host=new Host();
                List<Context> contextList=new ArrayList<>();
                host.setName(hostName);
                host.setPath(appbase);
                loadContextList(appbase,contextList);
                host.setContextList(contextList);
                hostList.add(host);
            }
            mapper.setHostList(hostList);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //根据host 中的路径，也就是webapp的路径，去加载context
    private void loadContextList(String appbase,List<Context> contextList) throws IllegalAccessException, InstantiationException {
      File file=new File(appbase);
      String[] list=file.list();
      for(int i=0;i<list.length;i++){
          String path=list[i];//demo1/demo2
          List<Wrapper> wrapperList=new ArrayList<>();
          //容器中存放class的实例
          HashMap<String,Object > classInstanceMap=new HashMap();
          // appbase+File.separator+path= Users/zhenghao/study/lagou_task/tomcat_task/webapp/demo2
          String localPath=appbase+File.separator+path;
          loadInstance( new File(localPath),classInstanceMap);
          loadeServlet(localPath,classInstanceMap,wrapperList);
          Context context=new Context();
          context.setPath(path);
          context.setWrapperList(wrapperList);
          contextList.add(context);
      }

    }

    //获取文件夹下面的class 文件
    private void loadInstance(File dir,HashMap<String,Object > classInstanceMap) throws InstantiationException, IllegalAccessException {
        File [] arr=dir.listFiles();
        for(File file:arr){
            if(file.isFile()&&file.getName().endsWith(".class")){
               //获取所有class 实例,key为server/name,value为反射实例
               Object o =MyClassLoader.getMyClass(file.getPath());
               classInstanceMap.put(o.getClass().getName(),o);
            }else if(file.isDirectory()){
                loadInstance(file,classInstanceMap);
            }
        }
    }



    private void loadeServlet(String path,HashMap<String,Object> classInstanceMap,List<Wrapper> list){
        try {
            InputStream resourceAsStream=new FileInputStream(path+File.separator+"web.xml");
            SAXReader saxReader=new SAXReader();
            Document document = saxReader.read(resourceAsStream);
            Element rootElement = document.getRootElement();

            List<Element> selectNodes = rootElement.selectNodes("//servlet");


            for (int i = 0; i < selectNodes.size(); i++) {
                Element element = selectNodes.get(i);
                // <servlet-name>lagou</servlet-name>
                Element servletnameElement = (Element) element.selectSingleNode("servlet-name");
                String servletName = servletnameElement.getStringValue();
                // <servlet-class>server.LagouServlet</servlet-class>
                Element servletclassElement = (Element) element.selectSingleNode("servlet-class");
                String servletClass = servletclassElement.getStringValue();
                // 根据servlet-name的值找到url-pattern
                Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
                // /lagou
                String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();
                Object instance=  classInstanceMap.get(servletClass);
                Wrapper wrapper=new Wrapper();
                wrapper.setPath(urlPattern);
                wrapper.setServlet(instance);
                list.add(wrapper);

            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
